package com.cf.aspect;

import com.cf.utils.RequestUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * @Author lzqinga@126.com
 * @Date 2024/12/7  9:36
 */
@Aspect
@Component
@Slf4j
public class LoggingAspect {

    // 定义切点，这里可以根据具体需求匹配不同的方法执行，比如匹配某个包下的所有方法
    @Pointcut("execution(* com.cf.controller.*.*(..))")
    public void controllerMethods() {}

    // 前置通知，在目标方法执行前记录日志
    @Before("controllerMethods()")
    public void beforeMethod(JoinPoint joinPoint) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        String ip = RequestUtil.getIpAddress(request);
        String userIdentifier = RequestUtil.getUserIdentifier(request);
        String methodName = joinPoint.getSignature().getName();

        log.info("IP: {} 用户: {} 开始访问方法: {}", ip, userIdentifier, methodName);
    }

    // 后置通知，在目标方法正常执行完成后记录日志
    @After("controllerMethods()")
    public void afterMethod(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        log.info("方法 {} 执行结束", methodName);
    }

    // 返回通知，记录方法成功返回的结果信息以及IP、用户等
    @AfterReturning(pointcut = "controllerMethods()", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        String ip = RequestUtil.getIpAddress(request);
        String userIdentifier = RequestUtil.getUserIdentifier(request);
        String methodName = joinPoint.getSignature().getName();

        log.info("IP: {} 用户: {} 方法 {} 返回结果: {}", ip, userIdentifier, methodName, result);
    }

    // 异常通知，记录方法抛出异常时的相关信息以及IP、用户等
    @AfterThrowing(pointcut = "controllerMethods()", throwing = "exception")
    public void afterThrowing(JoinPoint joinPoint, Throwable exception) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        String ip = RequestUtil.getIpAddress(request);
        String userIdentifier = RequestUtil.getUserIdentifier(request);
        String methodName = joinPoint.getSignature().getName();

        log.error("IP: {} 用户: {} 方法 {} 出现异常: {}", ip, userIdentifier, methodName, exception.getMessage());
    }
}
